﻿using WebApplication1.Services;

public interface ISessionManager
{
    Task<UserSession> CreateSessionAsync(WeChatUserInfo userInfo, WeChatTokenResponse tokenResponse);
    Task<bool> ValidateSessionAsync(string sessionId);
    Task<UserSession> GetSessionAsync(string sessionId);
    Task<bool> RefreshSessionAsync(string sessionId);
    Task<bool> RemoveSessionAsync(string sessionId);
    Task<bool> IsSessionExpiredAsync(string sessionId);
}

public class SessionManager : ISessionManager
{
    private readonly IRedisService _redisService;
    private readonly ILogger<SessionManager> _logger;
    private readonly TimeSpan _sessionExpiry = TimeSpan.FromMinutes(20); // 20分钟会话过期

    public SessionManager(IRedisService redisService, ILogger<SessionManager> logger)
    {
        _redisService = redisService;
        _logger = logger;
    }

    public async Task<UserSession> CreateSessionAsync(WeChatUserInfo userInfo, WeChatTokenResponse tokenResponse)
    {
        var sessionId = GenerateSessionId();

        var session = new UserSession
        {
            SessionId = sessionId,
            OpenId = userInfo.OpenId,
            UserInfo = userInfo,
            AccessToken = tokenResponse.AccessToken,
            RefreshToken = tokenResponse.RefreshToken,
            CreatedAt = DateTime.UtcNow,
            LastAccessedAt = DateTime.UtcNow,
            ExpiresAt = DateTime.UtcNow.Add(_sessionExpiry)
        };

        // 存储会话信息
        var sessionKey = GetSessionKey(sessionId);
        var openIdKey = GetOpenIdSessionKey(userInfo.OpenId);

        await _redisService.SetAsync(sessionKey, session, _sessionExpiry);
        await _redisService.SetAsync(openIdKey, sessionId, _sessionExpiry);

        _logger.LogInformation("创建用户会话: OpenId={OpenId}, SessionId={SessionId}", userInfo.OpenId, sessionId);

        return session;
    }

    public async Task<bool> ValidateSessionAsync(string sessionId)
    {
        if (string.IsNullOrEmpty(sessionId))
            return false;

        var session = await GetSessionAsync(sessionId);
        if (session == null)
            return false;

        // 更新最后访问时间
        session.LastAccessedAt = DateTime.UtcNow;
        var sessionKey = GetSessionKey(sessionId);
        await _redisService.SetAsync(sessionKey, session, _sessionExpiry);

        return true;
    }

    public async Task<UserSession> GetSessionAsync(string sessionId)
    {
        if (string.IsNullOrEmpty(sessionId))
            return null;

        var sessionKey = GetSessionKey(sessionId);
        return await _redisService.GetAsync<UserSession>(sessionKey);
    }

    public async Task<bool> RefreshSessionAsync(string sessionId)
    {
        var session = await GetSessionAsync(sessionId);
        if (session == null)
            return false;

        // 延长会话过期时间
        session.ExpiresAt = DateTime.UtcNow.Add(_sessionExpiry);
        session.LastAccessedAt = DateTime.UtcNow;

        var sessionKey = GetSessionKey(sessionId);
        var openIdKey = GetOpenIdSessionKey(session.OpenId);

        await _redisService.SetAsync(sessionKey, session, _sessionExpiry);
        await _redisService.SetAsync(openIdKey, sessionId, _sessionExpiry);

        _logger.LogInformation("刷新用户会话: OpenId={OpenId}, SessionId={SessionId}", session.OpenId, sessionId);

        return true;
    }

    public async Task<bool> RemoveSessionAsync(string sessionId)
    {
        var session = await GetSessionAsync(sessionId);
        if (session == null)
            return false;

        var sessionKey = GetSessionKey(sessionId);
        var openIdKey = GetOpenIdSessionKey(session.OpenId);

        await _redisService.RemoveAsync(sessionKey);
        await _redisService.RemoveAsync(openIdKey);

        _logger.LogInformation("删除用户会话: OpenId={OpenId}, SessionId={SessionId}", session.OpenId, sessionId);

        return true;
    }

    public async Task<bool> IsSessionExpiredAsync(string sessionId)
    {
        var session = await GetSessionAsync(sessionId);
        if (session == null)
            return true;

        return session.ExpiresAt <= DateTime.UtcNow;
    }

    private string GenerateSessionId()
    {
        return Convert.ToBase64String(Guid.NewGuid().ToByteArray())
                     .Replace("+", "").Replace("/", "").Replace("=", "");
    }

    private string GetSessionKey(string sessionId) => $"session:{sessionId}";
    private string GetOpenIdSessionKey(string openId) => $"openid_session:{openId}";
}